package com.kws.tool.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kws.common.core.enums.ModelOpType;
import com.kws.common.core.exception.ServiceException;
import com.kws.common.core.sys.Ksys;
import com.kws.common.core.utils.KConstants;
import com.kws.common.security.auth.AuthUtil;
import com.kws.common.security.service.TokenService;
import com.kws.common.security.utils.SecurityUtils;
import com.kws.system.api.domain.SysUser;
import com.kws.system.api.model.LoginUser;
import com.kws.tool.dto.*;
import com.kws.tool.entity.CollectEntity;
import com.kws.tool.entity.PolicyEntity;
import com.kws.tool.entity.PolicyLocationEntity;
import com.kws.tool.entity.StandardEntity;
import com.kws.tool.mapper.PolicyMapper;
import com.kws.tool.mapper.StandardMapper;
import com.kws.tool.service.CollectService;
import com.kws.tool.service.PolicyLocationService;
import com.kws.tool.service.PolicyService;
import com.kws.tool.service.StandardService;
import com.kws.tool.vo.LocationVo;
import com.kws.tool.vo.PolicyVo;
import com.kws.tool.vo.StandardVo;
import com.kws.tool.vo.ToolTypeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : zhangbenting
 * @date : 2024/10/22 10:49
 * @Version: 1.0
 */
@Service
public class PolicyServiceImpl extends ServiceImpl<PolicyMapper, PolicyEntity>
        implements PolicyService {

    @Resource
    private PolicyMapper policyMapper;

    @Resource
    private StandardMapper standardMapper;

    @Autowired
    private StandardService standardService;

    @Autowired
    private PolicyLocationService policyLocationService;

    @Autowired
    private CollectService collectService;


    @Override
    public Page<PolicyVo> getPolicyList(PolicyDto policyDto) {
        SysUser sysUser = AuthUtil.getLoginUser().getSysUser();
        Long userId = sysUser.getUserId();
        policyDto.setPageSize((policyDto.getPageSize() - 1) * policyDto.getTotalPage());
        LambdaQueryWrapper<PolicyEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StringUtils.isNotBlank(policyDto.getPolicyName()),
                PolicyEntity::getPolicyName, policyDto.getPolicyName());
        wrapper.eq(StringUtils.isNotBlank(policyDto.getLevel()),
                PolicyEntity::getLevel, policyDto.getLevel());
        wrapper.eq(StringUtils.isNotBlank(policyDto.getEconomize()),
                PolicyEntity::getEconomize, policyDto.getEconomize());
        wrapper.eq(StringUtils.isNotBlank(policyDto.getMarket()),
                PolicyEntity::getMarket, policyDto.getMarket());
        wrapper.eq(StringUtils.isNotBlank(policyDto.getDistrict()),
                PolicyEntity::getDistrict, policyDto.getDistrict());
        wrapper.in(ObjectUtils.isNotNull(policyDto.getOrgan()),
                PolicyEntity::getOrgan, policyDto.getOrgan());
        List<String> timeSection = policyDto.getTimeSection();
        if (ObjectUtils.isNotNull(timeSection)) {
            Date start = null;
            Date end = null;
            try {
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                start = formatter.parse(timeSection.get(0));
                end = formatter.parse(timeSection.get(1));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            wrapper.between(ObjectUtils.isNotNull(policyDto.getTimeSection())
                    , PolicyEntity::getCreateTime, start, end);
        }
        long count = this.count(wrapper);
        Page<PolicyVo> page = new Page<>(policyDto.getPageSize(), policyDto.getTotalPage(), count);
        if (count > 0) {
            String policyOrganStr = "";
            if (ObjectUtils.isNotNull(policyDto.getOrgan())) {
                policyOrganStr = policyDto.getOrgan().stream()
                        .map(account -> "\'" + account + "\'")
                        .collect(Collectors.joining(", "));
            }
            String startTime = "";
            String endTime = "";
            if (ObjectUtils.isNotNull(timeSection)){
                startTime = timeSection.get(0);
                endTime = timeSection.get(1);
            }
            List<PolicyVo> policyList = policyMapper.getPolicyList(policyDto.getPageSize(),
                    policyDto.getTotalPage(), policyDto.getPolicyName(), policyDto.getLevel(),
                    policyDto.getEconomize(), policyDto.getMarket(), policyDto.getDistrict(),
                    policyOrganStr, userId, startTime, endTime);
            policyList.forEach(item -> {
                if (ObjectUtils.isNotNull(item.getCollectId())) {
                    item.setIsCollect("1");
                } else {
                    item.setIsCollect("0");
                }
            });
            page.setRecords(policyList);
        }
        return page;
    }

    @Override
    public Page<StandardVo> getStandardList(StandardDto standardDto) {
        SysUser sysUser = AuthUtil.getLoginUser().getSysUser();
        Long userId = sysUser.getUserId();
        standardDto.setPageSize((standardDto.getPageSize() - 1) * standardDto.getTotalPage());
        LambdaQueryWrapper<StandardEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StringUtils.isNotBlank(standardDto.getStandardName()),
                StandardEntity::getStandardName, standardDto.getStandardName());
        wrapper.eq(StringUtils.isNotBlank(standardDto.getToolType()),
                StandardEntity::getToolType, standardDto.getToolType());
        List<String> timeSection = standardDto.getTimeSection();
        if (ObjectUtils.isNotNull(timeSection)) {
            Date start = null;
            Date end = null;
            try {
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                start = formatter.parse(timeSection.get(0));
                end = formatter.parse(timeSection.get(1));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            wrapper.between(ObjectUtils.isNotNull(standardDto.getTimeSection())
                    , StandardEntity::getCreateTime, start, end);
        }
        long count = standardService.count(wrapper);
        Page<StandardVo> page = new Page<>(standardDto.getPageSize(), standardDto.getTotalPage(), count);
        if (count > 0) {
            String startTime = "";
            String endTime = "";
            if (ObjectUtils.isNotNull(timeSection)){
                startTime = timeSection.get(0);
                endTime = timeSection.get(1);
            }
            List<StandardVo> standardList = standardMapper.getStandardList(standardDto.getPageSize(),
                    standardDto.getTotalPage(), standardDto.getStandardName(),
                    standardDto.getToolType(), userId,
                    startTime, endTime);
            standardList.forEach(item -> {
                if (ObjectUtils.isNotNull(item.getCollectId())) {
                    item.setIsCollect("1");
                } else {
                    item.setIsCollect("0");
                }
            });
            page.setRecords(standardList);
        }
        return page;
    }

    @Override
    public List<LocationVo> getLocationList() {
        List<PolicyLocationEntity> list = policyLocationService.list();
        if (list != null && list.size() > 0) {
            List<LocationVo> locationVos = new ArrayList<>();
            for (PolicyLocationEntity policyLocationEntity : list) {
                LocationVo locationVo = new LocationVo();
                locationVo.setId(policyLocationEntity.getId());
                locationVo.setPId(policyLocationEntity.getPId());
                locationVo.setName(policyLocationEntity.getName());
                locationVos.add(locationVo);
            }
            return getTree(locationVos);
        }
        return null;
    }

    @Override
    public LevelAndOrganDto getPolicyLevelAndOrgan() {
        List<PolicyEntity> list = this.list();
        List<String> levelList = list.stream().map(PolicyEntity::getLevel).filter(Objects::nonNull)
                .distinct().collect(Collectors.toList());
        List<String> organList = list.stream().map(PolicyEntity::getOrgan).filter(Objects::nonNull)
                .distinct().collect(Collectors.toList());
        LevelAndOrganDto levelAndOrganDto = new LevelAndOrganDto();

        List<LevelAndOrganDto.Level> levels = new ArrayList<>();
        for (String s : levelList) {
            LevelAndOrganDto.Level level = new LevelAndOrganDto.Level();
            level.setLevel(s);
            levels.add(level);
        }
        levelAndOrganDto.setLevelList(levels);

        List<LevelAndOrganDto.Organ> organs = new ArrayList<>();
        for (String s : organList) {
            LevelAndOrganDto.Organ organ = new LevelAndOrganDto.Organ();
            organ.setOrgan(s);
            organs.add(organ);
        }
        levelAndOrganDto.setOrganList(organs);

        return levelAndOrganDto;
    }

    @Override
    public boolean addPolicyOrStandardCollect(CollectDto collectDto) {
        String addType = collectDto.getAddType();
        SysUser sysUser = AuthUtil.getLoginUser().getSysUser();
        Long userId = sysUser.getUserId();
        Long collectTypeId = "0".equals(addType) ? collectDto.getPolicyId() : collectDto.getStandardId();
        String collectType = "0".equals(addType) ? "0" : "1";

        // 检查是否已经收藏
        if (isAlreadyCollected(collectTypeId, collectType,userId)) {
            throw new ServiceException("您已收藏该" + ("0".equals(addType) ? "政策" : "标准"));
        }

        // 创建并保存收藏记录
        CollectEntity collectEntity = new CollectEntity();
        collectEntity.setUserId(userId);
        collectEntity.setCollectTypeId(collectTypeId);
        collectEntity.setCollectType(collectType);
        return collectService.save(collectEntity);
    }

    @Override
    public boolean removePolicyOrStandardCollect(CollectDto collectDto) {
        String addType = collectDto.getAddType();
        SysUser sysUser = AuthUtil.getLoginUser().getSysUser();
        Long userId = sysUser.getUserId();
        Long collectTypeId = "0".equals(addType) ? collectDto.getPolicyId() : collectDto.getStandardId();

        CollectEntity collectEntity = getCollectEntity(collectTypeId,addType, userId);
        if (collectEntity == null) {
            return false;
        }
        return collectService.removeById(collectEntity);
    }

    // 提取查询逻辑
    private boolean isAlreadyCollected(Long collectTypeId, String collectType,Long userId) {
        LambdaQueryWrapper<CollectEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CollectEntity::getCollectTypeId, collectTypeId);
        wrapper.eq(CollectEntity::getUserId, userId);
        wrapper.eq(CollectEntity::getCollectType, collectType);
        CollectEntity entity = collectService.getOne(wrapper);
        return !ObjectUtils.isEmpty(entity);
    }

    // 提取获取收藏实体的逻辑
    private CollectEntity getCollectEntity(Long collectTypeId,String addType, Long userId) {
        LambdaQueryWrapper<CollectEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CollectEntity::getCollectTypeId, collectTypeId);
        wrapper.eq(CollectEntity::getUserId, userId);
        wrapper.eq(CollectEntity::getCollectType, addType);
        return collectService.getOne(wrapper);
    }

    @Override
    public boolean addPolicyOrStandardBrowse(CollectDto collectDto) {
        String addType = collectDto.getAddType();
        if ("0".equals(addType)) {
            LambdaQueryWrapper<PolicyEntity> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(PolicyEntity::getId, collectDto.getPolicyId());
            PolicyEntity policyEntity = this.getOne(wrapper);
            if (ObjectUtils.isEmpty(policyEntity)) return false;
            policyEntity.setPageView(policyEntity.getPageView() + 1);
            return this.saveOrUpdate(policyEntity);
        } else if ("1".equals(addType)) {
            LambdaQueryWrapper<StandardEntity> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(StandardEntity::getId, collectDto.getStandardId());
            StandardEntity standardEntity = standardService.getOne(wrapper);
            if (ObjectUtils.isEmpty(standardEntity)) return false;
            standardEntity.setPageView(standardEntity.getPageView() + 1);
            return standardService.saveOrUpdate(standardEntity);
        }
        return false;
    }

    @Override
    public Page<PolicyEntity> queryPolicyMaintenancePage(QueryPolicyMaintenanceRq rq) {
        Page<PolicyEntity> page = new Page<>(rq.getPageNum(), rq.getPageSize());
        Page<PolicyEntity> pageInfo = baseMapper.queryPolicyMaintenancePage(page, rq);
        return pageInfo;
    }

    @Override
    public boolean createPolicyMaintenance(CreatePolicyMaintenanceRq rq) {
        PolicyEntity policyEntity = new PolicyEntity();
        BeanUtil.copyProperties(rq, policyEntity);
        Ksys.setBasicModelData(policyEntity, SecurityUtils.getStringUserId(), KConstants.DATA_ENABLE, ModelOpType.CREATE);
        int insert = baseMapper.insert(policyEntity);
        if (1 == insert) {
            return true;
        }
        return false;
    }

    @Override
    public PolicyEntity queryPolicyMaintenanceById(Long id) {
        PolicyEntity policyEntity = baseMapper.selectById(id);
        return policyEntity;
    }

    @Override
    public boolean updatePolicyMaintenance(UpdatePolicyMaintenanceRq rq) {
        PolicyEntity policyEntity = baseMapper.selectById(rq.getId());
        BeanUtil.copyProperties(rq, policyEntity);
        Ksys.setBasicModelData(policyEntity, SecurityUtils.getStringUserId(), KConstants.DATA_ENABLE, ModelOpType.UPDATE);
        int i = baseMapper.updateById(policyEntity);
        if (1 == i) {
            return true;
        }
        return false;
    }

    @Override
    public boolean deletePolicyMaintenanceById(Long id) {
        UpdateWrapper updateWrapper = new UpdateWrapper();
        updateWrapper.eq("id", id);
        updateWrapper.set("enable", "0");
        updateWrapper.set("update_user", SecurityUtils.getUserId());
        updateWrapper.set("update_time", new Date());
        int update = baseMapper.update(null, updateWrapper);
        if (1 == update) {
            return true;
        }
        return false;
    }

    @Override
    public List<ToolTypeVo> getStandardToolType() {
        List<StandardEntity> list = standardService.list();
        List<String> stringList = list.stream().map(StandardEntity::getToolType).distinct().collect(Collectors.toList());
        List<ToolTypeVo> toolTypeVos = new ArrayList<>();
        for (String s : stringList) {
            ToolTypeVo toolTypeVo = new ToolTypeVo();
            toolTypeVo.setToolType(s);
            toolTypeVos.add(toolTypeVo);
        }
        return toolTypeVos;
    }

    @Override
    public Page<StandardVo> getStandardCollectList(StandardDto standardDto) {
        standardDto.setPageSize((standardDto.getPageSize() - 1) * standardDto.getTotalPage());
        SysUser sysUser = AuthUtil.getLoginUser().getSysUser();
        Long userId = sysUser.getUserId();
        LambdaQueryWrapper<CollectEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CollectEntity::getUserId, userId);
        wrapper.eq(CollectEntity::getCollectType, 1);
        long count = collectService.count(wrapper);
        Page<StandardVo> page = new Page<>(standardDto.getPageSize(),standardDto.getTotalPage(), count);
        if (count > 0){
            String startTime = "";
            String endTime = "";
            List<String> timeSection = standardDto.getTimeSection();
            if (ObjectUtils.isNotNull(timeSection)){
                startTime = timeSection.get(0);
                endTime = timeSection.get(1);
            }
            List<StandardVo> standardList = standardMapper.getUserCollectStandardList(standardDto.getPageSize(),
                    standardDto.getTotalPage(), standardDto.getStandardName(),
                    standardDto.getToolType(), userId,startTime, endTime);
            standardList.forEach(item -> {
                item.setIsCollect("1");
            });
            page.setRecords(standardList);
        }
        return page;
    }

    @Override
    public Page<PolicyVo> getPolicyCollectList(PolicyDto policyDto) {
        policyDto.setPageSize((policyDto.getPageSize() - 1) * policyDto.getTotalPage());
        SysUser sysUser = AuthUtil.getLoginUser().getSysUser();
        Long userId = sysUser.getUserId();
        LambdaQueryWrapper<CollectEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CollectEntity::getUserId, userId);
        wrapper.eq(CollectEntity::getCollectType, 0);
        long count = collectService.count(wrapper);
        Page<PolicyVo> page = new Page<>(policyDto.getPageSize(),policyDto.getTotalPage(), count);
        if(count>0){
            String policyOrganStr = "";
            if (ObjectUtils.isNotNull(policyDto.getOrgan())) {
                policyOrganStr = policyDto.getOrgan().stream()
                        .map(account -> "\'" + account + "\'")
                        .collect(Collectors.joining(", "));
            }
            String startTime = "";
            String endTime = "";
            List<String> timeSection = policyDto.getTimeSection();
            if (ObjectUtils.isNotNull(timeSection)){
                startTime = timeSection.get(0);
                endTime = timeSection.get(1);
            }
            List<PolicyVo> policyList = policyMapper.getUserCollectPolicyList(policyDto.getPageSize(),
                    policyDto.getTotalPage(), policyDto.getPolicyName(), policyDto.getLevel(),
                    policyDto.getEconomize(), policyDto.getMarket(), policyDto.getDistrict(),
                    policyOrganStr, userId, startTime, endTime);
            if (policyList != null && policyList.size() > 0){
                policyList.forEach(data->{
                    data.setIsCollect("1");
                });
            }
            page.setRecords(policyList);
        }
        return page;
    }


    public List<LocationVo> getTree(List<LocationVo> locationVos) {
        Map<Long, List<LocationVo>> childrenMap = new HashMap<>();
        Set<Long> rootIds = new HashSet<>();

        for (LocationVo locationVo : locationVos) {
            Long pId = locationVo.getPId();
            if (pId == null) {
                pId = 0L; // 假设 pId 为 null 时，默认为根节点
            }

            childrenMap.computeIfAbsent(pId, k -> new ArrayList<>()).add(locationVo);
            if (pId.equals(0L)) {
                rootIds.add(locationVo.getId());
            }
        }

        List<LocationVo> tree = new ArrayList<>();
        for (Long rootId : rootIds) {
            LocationVo root = findLocationById(rootId, locationVos);
            if (root != null) {
                root.setChildren(getChildren(rootId, childrenMap));
                tree.add(root);
            }
        }

        return tree;
    }

    private LocationVo findLocationById(Long id, List<LocationVo> locationVos) {
        for (LocationVo locationVo : locationVos) {
            if (locationVo.getId().equals(id)) {
                return locationVo;
            }
        }
        return null;
    }

    private List<LocationVo> getChildren(Long parentId, Map<Long, List<LocationVo>> childrenMap) {
        List<LocationVo> children = childrenMap.getOrDefault(parentId, Collections.emptyList());
        for (LocationVo child : children) {
            child.setChildren(getChildren(child.getId(), childrenMap));
        }
        return children;
    }

}
